package com.zyj.core.executor;

import com.zyj.core.cache.Cache;
import com.zyj.core.cache.TransactionalCacheManager;
import com.zyj.core.config.Configuration;
import com.zyj.core.config.MappedStatement;

import java.util.List;

/**
 * 带有二级缓存功能的处理器，并不是真正查询数据库的执行器
 */
public class CachingExecutor implements Executor {
    /**
     * 装饰器模式
     */

    // 真正干活的执行器
    private Executor delegate;

    /**
     * 二级缓存管理器
     */
    private TransactionalCacheManager tcm = new TransactionalCacheManager();


    /**
     * 装饰器模式
     *
     * @param delegate
     */
    public CachingExecutor(Executor delegate) {
        this.delegate = delegate;
    }

    /**
     * 装饰器模式
     *
     * @param configuration
     * @param ms
     * @param param
     * @param <T>
     * @return
     */
    @Override
    public <T> List<T> query(Configuration configuration, MappedStatement ms, Object param) {

//        TODO 二级缓存的处理
        // 可以从ms中获取它的二级缓存对象
        Cache cache = ms.getCache();


        // todo 如何查询二级缓存呢？ 需要从ms中获取二级缓存再进行操作

        /**
         * 使用之所以要使用装饰器模式增强BaseExecutor，是因为在调用BaseExecutor进行查询之前，需要先在CachingExecutor中完成二级缓存的查询
         */

        /**
         * 在此处要查询二级缓存【默认开启但是还需要进一步才生效】
         *
         * 缓存的优先级
         * 通过mybatis发起的查询，作用顺序为：二级缓存->一级缓存->数据库 ，其中任何一个环节查到不为空的数据，都将直接返回结果
         *
         * 默认情况下，mybatis打开了二级缓存，但它并未生效，因为二级缓存的作用域是namespace，所以还需要在Mapper.xml文件中配置一下才能使二级缓存生效.
         * 所以其实本质上二级缓存是默认不开启的
         *
         * 一级缓存的作用范围：一级缓存的作用域是SqlSession级别
         * 二级缓存的作用范围：二级缓存的作用域是namespace级别
         *
         * 一级缓存因为只能在同一个SqlSession中共享，所以会存在一个问题，在分布式或者多线程的环境下，不同会话之间对于相同的数据可能会产生不同的结果，因为跨会话修改了数据是不能互相感知的，
         * 所以就有可能存在脏数据的问题，正因为一级缓存存在这种不足，所以我们需要一种作用域更大的缓存，这就是二级缓存。
         */

        // 如果没有配置二级缓存，则走真正的处理器
        return delegate.query(configuration, ms, param);
    }
}
